package org.nerve.hibernate;

import org.apache.commons.lang3.time.DateUtils;
import org.hibernate.criterion.*;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 动态查询实现类
 * org.nerve.hibernate
 * Created by zengxm on 2016/3/11 0011.
 */
public class DynamicQuery implements Serializable{

	/**
	 * 存放各种实体的字段信息
	 */
	private static final Map<String,Map<String,String>> fieldMap=new ConcurrentHashMap<>();

	/**
	 * 各种用于解析日期格式
	 */
	private static String[] parsePatterns = { "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm",
			"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm" };

	/**
	 * 先尝试从fieldMap中获取字段信息，如果没有则通过java反射获取实体的字段信息
	 * 然后保存到fieldMap中，以便下次使用
	 * @param clzss
	 * @return
	 */
	private static Map<String,String> buildOrCreateFieldMap(Class clzss){
		String key=clzss.getName();
		if(fieldMap.containsKey(key)){
			return fieldMap.get(key);
		}

		Field[] fields=clzss.getDeclaredFields();

		final Map<String, String> map=new ConcurrentHashMap<String, String>();
		for(Field f:fields)
			map.put(f.getName(), f.getType().toString());
		fieldMap.put(key, map);
		return map;
	}


	/**
	 * 返回的是 DetachedCriteria （无需Session的离线Criteria）
	 * @param clzss
	 * @param map
	 * @return
	 */
	public static DetachedCriteria build(Class clzss, Map<String,Object> map){
		final DetachedCriteria dc = DetachedCriteria.forClass(clzss);
		Map<String,String> fieldM = buildOrCreateFieldMap(clzss);

		if(map.size()>0){
			for(Iterator<String> keys = map.keySet().iterator(); keys.hasNext();){
				String k=keys.next();
				Object v=map.get(k);
				if(v == null || v.toString().trim().length()==0)
					continue;

				String t[] = k.split("_");
				if(t.length<2)
					continue;

				//进行类型转换
				String fieldType=fieldM.get(t[1]);
				if("class java.lang.String".equals(fieldType))
					try{v = (String)v;}catch (Exception e){}
				else if("int".equals(fieldType) || "class java.lang.Integer".equals(fieldType))
					try{v = Integer.valueOf((String)v);}catch (Exception e){}
				else if("long".equals(fieldType) || "class java.lang.Long".equals(fieldType))
					try{v = Long.valueOf((String)v);}catch (Exception e){}
				else if("float".equals(fieldType) || "class java.lang.Float".equals(fieldType))
					try{v = Float.valueOf((String)v);}catch (Exception e){}
				else if("double".equals(fieldType) || "class java.lang.Bouble".equals(fieldType))
					try{v = Double.valueOf((String)v);}catch (Exception e){}
				else if("class java.util.Date".equals(fieldType)){
					try {
						v = DateUtils.parseDate((String)v, parsePatterns);
					}catch (Exception e){}
				}


				t[0]=t[0].toUpperCase();
				if(t[0].equals("LIKE")){
					String like=(String)v;
					//如果不是以%开头或者结尾，就给前后都加上%
					if(!(like.startsWith("%")||like.endsWith("%")))
						like="%"+like+"%";
					if(t.length==2) dc.add(Restrictions.like(t[1], like));
					else{
						Disjunction dis=Restrictions.disjunction();
						for(int i=1;i<t.length;i++){
							dis.add(Restrictions.like(t[i], like, MatchMode.ANYWHERE));
						}
						dc.add(dis);
					}
				}else if(t[0].equals("EQ"))
					dc.add(Restrictions.eq(t[1],v));
				else if(t[0].equals("IN"))
					dc.add(Restrictions.in(t[1], (Object[])v));
				else if(t[0].equals("GT"))
					dc.add(Restrictions.gt(t[1], v));
				else if(t[0].equals("GTE"))
					dc.add(Restrictions.ge(t[1],v));
				else if(t[0].equals("LT"))
					dc.add(Restrictions.lt(t[1],v));
				else if(t[0].equals("LTE"))
					dc.add(Restrictions.le(t[1],v));
				else if(t[0].equals("NOT"))
					dc.add(Restrictions.not(Restrictions.like(t[1],v)));
				else if(t[0].equals("SORT")){
					if(v.toString().equals("1")||v.toString().equalsIgnoreCase("DESC"))
						dc.addOrder(Order.desc(t[1]));
					else
						dc.addOrder(Order.asc(t[1]));
				}
			}
		}
		return dc;
	}
}
